// NOTE: this file was gotten online

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "pngLoader.h"

// link with library
//#pragma comment(lib, "libpng.lib")
//#pragma comment(lib, "zlib.lib")

void Png::abort_(const char * s, ...)
{
	va_list args;
	va_start(args, s);
	vfprintf(stderr, s, args);
	fprintf(stderr, "\n");
	va_end(args);
	exit(0);
}

void Png::loadPng(const char* file_name)
{
	if(data!=0)
	{
		delete[] data;
	}

	png_byte color_type;
	png_byte bit_depth;

	png_structp png_ptr;
	png_infop info_ptr;
	png_infop png_end;
	png_bytep* png_rows;

	char header[8];	// 8 is the maximum size that can be checked

	// open file and test for it being a png
	FILE *fp = fopen(file_name, "rb");
	if (!fp)
		abort_("[read_png_file] File %s could not be opened for reading", file_name);
	fread(header, 1, 8, fp);
	if (png_sig_cmp((png_bytep)header, 0, 8) != 0)
		abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);

	/* initialize stuff */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png_ptr)
		abort_("[read_png_file] png_create_read_struct failed");

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
		abort_("[read_png_file] png_create_info_struct failed");

	png_end = png_create_info_struct(png_ptr);

	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[read_png_file] Error during init_io");

	png_set_sig_bytes(png_ptr, 8);
	png_init_io(png_ptr, fp);

	png_read_info(png_ptr, info_ptr);

	width = png_get_image_width(png_ptr, info_ptr);
	height = png_get_image_height(png_ptr, info_ptr);

	bit_depth = png_get_bit_depth(png_ptr, info_ptr);
	color_type = png_get_color_type(png_ptr, info_ptr);

	// Set color type and bit depth according to png info
	if (color_type == PNG_COLOR_TYPE_PALETTE)
	{
		png_set_palette_to_rgb(png_ptr);
	}
	if (color_type == PNG_COLOR_TYPE_GRAY || color_type
			== PNG_COLOR_TYPE_GRAY_ALPHA)
	{
		png_set_gray_to_rgb(png_ptr);
	}
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
	{
		png_set_expand(png_ptr);
		png_set_tRNS_to_alpha(png_ptr);
	}
	else
	{
		png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
	}
	if (bit_depth == 16)
	{
		png_set_strip_16(png_ptr);
	}

	png_read_update_info(png_ptr, info_ptr);

	// png data will hold the image data in OpenGL format order.
	data = (png_bytep) malloc(4 * width * height);
	png_rows = (png_bytep*) malloc(height * sizeof(png_bytep));

	for (unsigned int row = 0; row < height; ++row)
	{
		png_rows[height - 1 - row] = data + (row * 4 * width);
	}

	png_read_image(png_ptr, png_rows);

	free(png_rows);

	png_destroy_read_struct(&png_ptr, &info_ptr, &png_end);

	fclose(fp);
	return;
}

// end of pngLoader.cpp
